//
//  QDailyAPI.m
//  FakeQDaily
//
//  Created by mewxiv on 8/12/16.
//  Copyright © 2016 Xensius. All rights reserved.
//

#import "QDailyAPI.h"
#import "QDailyAPIConstants.h"
#import "FQDMultipartFileData.h"

#import "AFNetworking.h"

@interface QDailyAPI ()
@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;
@end

@implementation QDailyAPI

#pragma mark - Configuration

+ (instancetype)sharedAPI
{
    static QDailyAPI *sharedAPI;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedAPI = [[QDailyAPI alloc] init];
    });
    return sharedAPI;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setupSessionManager];
        [self setupUserAgent];
    }
    return self;
}

- (void)dealloc
{
    
}

- (void)setupSessionManager
{
    NSURL *baseURL = [NSURL URLWithString:QDailyBaseURL];
    _sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
}

- (void)setupUserAgent
{
    NSString *userAgent = [_sessionManager.requestSerializer valueForHTTPHeaderField:@"User-Agent"];
    userAgent = [userAgent stringByAppendingFormat:@" QDaily/%@", QDailyBundleVersion];
//    [_sessionManager.requestSerializer setValue:@"User-Agent" forHTTPHeaderField:userAgent];
    [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent": userAgent}];
}

- (void)getJson:(NSString *)endpoint parameters:(id)parameters completion:(QDailyAPICompleteBlock)completion
{
    [self get:[endpoint stringByAppendingString:@".json"] parameters:parameters completion:completion];
}

- (void)get:(NSString *)endpoint parameters:(id)parameters completion:(QDailyAPICompleteBlock)completion
{
    [self.sessionManager GET:endpoint
     parameters:parameters
     progress:nil
     success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
        [self checkResponseHeaders:(NSHTTPURLResponse *)task.response];
        completion ? completion(responseObject, nil) : nil;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        completion ? completion(nil, error) : nil;
    }];
}

- (void)post:(NSString *)endpoint parameters:(id)parameters completion:(QDailyAPICompleteBlock)completion
{
    [self.sessionManager POST:endpoint
     parameters:parameters
     progress:nil
     success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
        [self checkResponseHeaders:(NSHTTPURLResponse *)task.response];
        completion ? completion(responseObject, nil) : nil;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        completion ? completion(nil, error) : nil;
    }];
}

- (void)post:(NSString *)endpoint parameters:(id)parameters bodyFormData:(NSDictionary *)bodyFormData completion:(QDailyAPICompleteBlock)completion
{
    [self post:endpoint parameters:parameters bodyFormData:bodyFormData partFileDatas:nil completion:completion];
}


- (void)post:(NSString *)endpoint parameters:(id)parameters bodyFormData:(NSDictionary *)bodyFormData partFileDatas:(NSDictionary *)partFileDatas completion:(QDailyAPICompleteBlock)completion;
{
    [self.sessionManager POST:endpoint
     parameters:parameters
     constructingBodyWithBlock:^(id < AFMultipartFormData > _Nonnull formData) {
         NSArray *sortedFieldNames = [bodyFormData allKeys];
         sortedFieldNames = [sortedFieldNames sortedArrayUsingComparator:
                             ^NSComparisonResult (NSString  *str1, NSString  *str2) {
                                 return [str1 compare:str2];
                             }];
        for (NSString *fieldName in sortedFieldNames) {
            NSData *fieldData = [bodyFormData[fieldName] dataUsingEncoding:NSUTF8StringEncoding];
            [formData appendPartWithFormData:fieldData name:fieldName];
        }

        for (NSString *fieldName in partFileDatas) {
            FQDMultipartFileData *partFileData = partFileDatas[fieldName];
            NSError *error = nil;
            [formData appendPartWithFileData:partFileData.data name:fieldName
             fileName:partFileData.fileName mimeType:partFileData.mimeType];
            if (error) {
                FQDLog(@"Failed to upload file:%@ reason:%@", partFileData.fileName, [error localizedDescription]);
            }
        }
    } progress:nil
     success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
        [self checkResponseHeaders:(NSHTTPURLResponse *)task.response];
        completion ? completion(responseObject, nil) : nil;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        completion ? completion(nil, error) : nil;
    }];
}

- (void)put:(NSString *)endpoint parameters:(id)parameters completion:(QDailyAPICompleteBlock)completion
{
    [self.sessionManager PUT:endpoint
     parameters:parameters
     success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
        [self checkResponseHeaders:(NSHTTPURLResponse *)task.response];
        completion ? completion(responseObject, nil) : nil;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        completion ? completion(nil, error) : nil;
    }];
}

- (void)delete:(NSString *)endpoint parameters:(id)parameters completion:(QDailyAPICompleteBlock)completion
{
    [self.sessionManager DELETE:endpoint
     parameters:parameters
     success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
        [self checkResponseHeaders:(NSHTTPURLResponse *)task.response];
        completion ? completion(responseObject, nil) : nil;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        completion ? completion(nil, error) : nil;
    }];
}

- (void)checkResponseHeaders:(NSHTTPURLResponse *)response
{
    if ([response respondsToSelector:@selector(allHeaderFields)]) {
        NSDictionary *allHeaderFields = [response allHeaderFields];
        
        if ([allHeaderFields objectForKey:@"Set-Cookie"]) {
            NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
            [defaultCenter postNotificationName:FQDAppCookiesDidChangeNotification
                                         object:self
                                       userInfo:nil];
        }
    }
}

- (NSString *)personalInfoNameForType:(QDailyPersonalInfoType)infoType
{
    static NSDictionary *personalInfoNameDict;
    if (!personalInfoNameDict) {
        personalInfoNameDict = @{
            @(QDailyPersonalInfoTypeAvatar)         : @"user[face]",
            @(QDailyPersonalInfoTypeUsername)       : @"user[username]",
            @(QDailyPersonalInfoTypeSignature)      : @"user[description]",
            @(QDailyPersonalInfoTypeEmail)          : @"user[email]",
            @(QDailyPersonalInfoTypeAddress)        : @"user[address]",
            @(QDailyPersonalInfoTypeMobile)         : @"user[phone]",
            @(QDailyPersonalInfoTypeCurPassword)    : @"user[current_password]",
            @(QDailyPersonalInfoTypePassword)       : @"user[password]",
            @(QDailyPersonalInfoTypeConfirmPass)    : @"user[password_confirmation]",
            @(QDailyPersonalInfoTypeStatus)         : @"user[status]",
            @(QDailyPersonalInfoTypeSource)         : @"user[source]",
        };
    }
    return personalInfoNameDict[@(infoType)];
}

#pragma mark - QDaily的API接口请求

- (void)registerWithEmail:(NSString *)email password:(NSString *)password completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *formData = @{
        @"user[email]" : email,
        @"user[password]" : password,
        @"user[password_confirmation]" : password,
    };
    [self post:QDailyRegisterURL parameters:nil bodyFormData:formData completion:completion];
}

- (void)completeRegisterWithEmail:(NSString *)email password:(NSString *)password
                         username:(NSString *)username signature:(NSString *)signature
               avatarPartFileData:(FQDMultipartFileData *)avatarPartFileData
                       completion:(QDailyAPICompleteBlock)completion
{
     NSDictionary *formData = @{
         @"user[email]"          : email,
         @"user[password]"       : password,
         @"user[username]"       : username,
         @"user[description]"    : signature,
         @"user[source]"         : FQDAppDownloadSource,
     };
    
    NSDictionary *partFileDatas = nil;
    if (avatarPartFileData) {
        NSString *avatarInfoName = [self personalInfoNameForType:QDailyPersonalInfoTypeAvatar];
        partFileDatas = @{
            avatarInfoName : avatarPartFileData
        };
    }
    
    [self post:QDailyCompleteRegisterURL parameters:nil bodyFormData:formData
     partFileDatas:partFileDatas completion:completion];
}

- (void)loginWithPhone:(NSString *)phone password:(NSString *)password remember:(BOOL)remember completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *formData = @{
        @"user[phone]" : phone,
        @"user[password]" : password,
        @"user[remember_me]" : (remember) ? @"1" : @"0",
    };
    [self post:QDailyPhoneLoginURL parameters:nil bodyFormData:formData completion:completion];
}

- (void)loginWithEmail:(NSString *)email password:(NSString *)password remember:(BOOL)remember completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *formData = @{
        @"user[email]" : email,
        @"user[password]" : password,
        @"user[remember_me]" : [@(remember) stringValue],
    };
    [self post:QDailyEmailLoginURL parameters:nil bodyFormData:formData completion:completion];
}

- (void)logout:(QDailyAPICompleteBlock)completion
{
    [self delete:QDailyLogoutURL parameters:nil completion:completion];
}

- (void)changePassword:(NSString *)currentPass newPassword:(NSString *)password completion:(QDailyAPICompleteBlock)completion
{
    NSString *currentPassName = [self personalInfoNameForType:QDailyPersonalInfoTypeCurPassword];
    NSString *passwordName = [self personalInfoNameForType:QDailyPersonalInfoTypePassword];
    NSString *confirmPassName = [self personalInfoNameForType:QDailyPersonalInfoTypeConfirmPass];
    NSDictionary *parameters = @{
        currentPassName : currentPass,
        passwordName : password,
        confirmPassName : password,
    };
    [self put:QDailyChangePasswordURL parameters:parameters completion:completion];
}

- (void)updatePersonalInfo:(QDailyPersonalInfoType)infoType infoValue:(NSString *)infoValue completion:(QDailyAPICompleteBlock)completion
{
    NSString *infoName = [self personalInfoNameForType:infoType];
    NSString *sourceName = [self personalInfoNameForType:QDailyPersonalInfoTypeSource];
    NSDictionary *formData = @{
        sourceName : FQDAppDownloadSource,
        infoName : infoValue,
    };
    [self post:QDailyUpdateUserPersonalInfoURL parameters:nil bodyFormData:formData completion:completion];
}

- (void)updateAvatarWithPartFileData:(FQDMultipartFileData *)partFileData completion:(QDailyAPICompleteBlock)completion;
{
    NSString *avatarName = [self personalInfoNameForType:QDailyPersonalInfoTypeAvatar];
    NSString *sourceName = [self personalInfoNameForType:QDailyPersonalInfoTypeSource];
    NSDictionary *formData = @{ sourceName : FQDAppDownloadSource };
    NSDictionary *partFileDatas = @{ avatarName : partFileData };
    [self post:QDailyUpdateUserPersonalInfoURL parameters:nil
     bodyFormData:formData partFileDatas:partFileDatas completion:completion];
}

- (void)getUserRadar:(QDailyAPICompleteBlock)completion
{
    [self get:QDailyUserRadarURL parameters:nil completion:completion];
}

- (void)getUserSubscription:(NSString *)userId completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *parameters = @{ @"user_id" : userId };
    [self get:QDailyUserSubscriptionURL parameters:parameters completion:completion];
}

- (void)getUserCenter:(QDailyAPICompleteBlock)completion
{
    [self get:QDailyUserCenterURL parameters:nil completion:completion];
}

- (void)addSubscribeColumn:(NSString *)columnId completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *formData = @{
        @"special_column_id" : columnId
    };
    [self post:QDailyColumnCenterAddSubscribeURL parameters:nil bodyFormData:formData completion:completion];
}

- (void)removeSubscribeColumn:(NSString *)columnId completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *formData = @{
        @"special_column_id" : columnId
    };
    [self post:QDailyColumnCenterRemoveSubscribeURL parameters:nil bodyFormData:formData completion:completion];
}

- (void)getColumnAuthorsAndSubscribersInfo:(NSString *)columnId completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyColumnAuthorsAndSubscribersInfoURLFormat, columnId];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)getHomeFeed:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyHomeFeedURLFormat, key];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)getSideBar:(QDailyAPICompleteBlock)completion
{
    [self getJson:QDailyHomeSideBarURL parameters:nil completion:completion];
}

- (void)getNewsCategoriesFeed:(NSString *)categoryId key:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyNewsCategoriesURLFormat, categoryId, key];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)searchArticle:(NSString *)keyword key:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *parameters = @{
        @"search" : keyword,
        @"last_key" : key,
    };
    
    [self get:QDailySearchArticleURL parameters:parameters completion:completion];
}

/*
 * 栏目中心
 */
- (void)getColumnFeed:(NSString *)columnId key:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyColumnFeedURLFormat, columnId, key];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)getColumnSubscriptionPosts:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *parameters = @{
        @"last_key" : key,
    };
    [self get:QDailyColumnCenterSubscriptionPostsURL parameters:parameters completion:completion];
}

- (void)getAllColumnsInColumnCenter:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyColumnCenterAllColumnsURLFormat, key];
    [self getJson:urlString parameters:nil completion:completion];
}

/*
 * 文章
 */
- (void)getArticleDetail:(NSString *)postId completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyArticleDetailURLFormat, postId];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)getArticleInfo:(NSString *)postId completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyArticleInfoURLFormat, postId];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)commentArticle:(NSString *)postId content:(NSString *)content parentCommentId:(NSString *)parentCommentId completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *formData = @{
        @"comment_type" : @"article",
        @"content" : content,
        @"id" : postId,
        @"parent_id" : parentCommentId,
    };
    [self post:QDailyArticleCreateCommentURL parameters:nil bodyFormData:formData completion:completion];
}

- (void)getArticleComments:(NSString *)postId key:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyArticleCommentsURLFormat, postId, key];
    [self getJson:urlString parameters:nil completion:completion];
    
}

- (void)praisePost:(NSString *)postId genre:(NSInteger)genre praiseType:(NSString *)praiseType completion:(QDailyAPICompleteBlock)complete
{
    NSDictionary *formData = @{
        @"id" : postId,
        @"genre" : [@(genre) stringValue],
        @"praise_type" : praiseType,
    };
    [self post:QDailyPraisePostURL parameters:nil bodyFormData:formData completion:complete];
}

- (void)getTaggedArticleList:(NSString *)tagId key:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyTaggedArticleListURLFormat, tagId, key];
    [self getJson:urlString parameters:nil completion:completion];
}

/*
 * 好奇心研究所
 */
- (void)getLabPaperList:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyLabPaperListURLFormat, key];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)getLabPaperDetail:(NSString *)postId completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyLabPaperDetailURLFormat, postId];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)getLabOptions:(NSString *)postId key:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyLabOptionsURLFormat, postId, key];
    [self getJson:urlString parameters:nil completion:completion];
}

- (void)sendLabVoteResultWithOptionIds:(NSArray *)optionIds paperId:(NSString *)paperId completion:(QDailyAPICompleteBlock)completion
{
    NSString *options = [optionIds componentsJoinedByString:@","];
    NSDictionary *formData = @{
        @"options" : options,
        @"paper_id" : paperId,
    };
    [self post:QDailyLabVoteResultURL parameters:nil bodyFormData:formData completion:completion];
}

/*
 * 我的消息
 */
- (void)getMyCommentMessages:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *parameters = @{
        @"last_key" : key,
    };
    [self get:QDailyMyMessageCommentOnMeURL parameters:parameters completion:completion];
}

- (void)getMyPraiseMessages:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *parameters = @{
        @"last_key" : key,
    };
    [self get:QDailyMyMessagePraiseOnMeURL parameters:parameters completion:completion];
}

- (void)getMySystemMessages:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *parameters = @{
        @"last_key" : key
    };
    [self get:QDailyMyMessageSystemMessageURL parameters:parameters completion:completion];
}

- (void)getMySendOutComments:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *parameters = @{
        @"last_key" : key
    };
    [self get:QDailyMyMessageSendOutCommentURL parameters:parameters completion:completion];
}

/*
 * 个人中心
 */
- (void)getUserPraisedArticleList:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *parameters = @{
        @"last_key" : key
    };
    [self get:QDailyUserCenterPraisedArticlesURL parameters:parameters completion:completion];
}

- (void)getUserJoinedLabResearchList:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSDictionary *paramters = @{
        @"last_key" : key,
    };
    [self get:QDailyUserCenterJoinedLabResearchURL parameters:paramters completion:completion];
}

- (void)getUserRadarArticleList:(NSString *)radarId key:(NSString *)key completion:(QDailyAPICompleteBlock)completion
{
    NSString *urlString = [NSString stringWithFormat:QDailyUserCenterRadarArticlesURLFormat, radarId, key];
    [self getJson:urlString parameters:nil completion:completion];
}

@end
